package com.lwl.concurrency.synchr;

import com.lwl.utils.SnowflakeIdWorker;

import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

/**<pre>
 * 所有线程调用了await()后,CyclicBarrier的计算器减为0,所有线程会自动继续执行,
 * 本案例用于检测雪花算法在高并发情况下的数据安全性
 * 可以指定runnable参数,用户在await()全部被调用后执行相关操作
 * 两种使用场景:await()方法
 *   1等待所有任务完成,继续后面的工作,该场景CountDownLatch也能实现
 *   2等待所有线程到达后,同时执行某个任务(本案例,用于检测雪花算法生成的主键的唯一性)
 *</pre>
 * @author liwenlong - 2018/3/28 14:05
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) throws UnknownHostException, InterruptedException {
        CyclicBarrierDemo demo = new CyclicBarrierDemo();
        for (int i = 0; i < 1; i++) {
            demo.snowflakeIdWorker();
        }
    }

    public void snowflakeIdWorker() throws UnknownHostException, InterruptedException {
        int count = 10;
        ConcurrentHashMap<Long,Long> data = new ConcurrentHashMap<>();
        CyclicBarrier barrier = new CyclicBarrier(count,()->{
            System.out.println("啊.我被猪@了 "+data.size());
        });
        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker();

        Thread[] threads = new Thread[count];

        for (int i = 0; i < count; i++) {
            Thread thread = new Thread(new GenerateId(barrier, snowflakeIdWorker, data));
            threads[i] = thread;
            System.out.println(thread.getName()+"启动");
            thread.start();
            TimeUnit.SECONDS.sleep(2);
            if (i == 5){
                thread.interrupt();
            }
        }

       /* for (int i = 0; i < count; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(data.size());
        */
        System.out.println(barrier.isBroken());
        System.out.println(barrier.getNumberWaiting());
        System.out.println(barrier.getParties());
        barrier.reset();
        System.out.println();
        System.out.println(barrier.isBroken());
        System.out.println(barrier.getNumberWaiting());
        System.out.println(barrier.getParties());

    }

    class GenerateId implements Runnable{
        private CyclicBarrier barrier;
        private SnowflakeIdWorker snowflakeId;
        private Map<Long,Long> data;

        public GenerateId(CyclicBarrier barrier,SnowflakeIdWorker snowflakeId,Map<Long,Long> data) {
            this.barrier = barrier;
            this.snowflakeId = snowflakeId;
            this.data = data;
        }

        @Override
        public void run() {
            try {
                //等待所有线程一起执行
                boolean broken = barrier.isBroken();
                if (broken){
                    System.out.println("循环栅栏等待的线程出现中断线程...");
                    return;
                }
                System.out.println(Thread.currentThread().getName()+"-开始等待...");
                barrier.await();

                System.out.println("全部开始执行...");
                TimeUnit.SECONDS.sleep(10);
                long id = snowflakeId.nextId();
                data.put(id,id);

                //等待所有线程执行完成
                barrier.await();

            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }



}
